// 
// -------------------------------------------------------------
//    Copyright 2004-2008 Synopsys, Inc.
//    All Rights Reserved Worldwide
// 
//    Licensed under the Apache License, Version 2.0 (the
//    "License"); you may not use this file except in
//    compliance with the License.  You may obtain a copy of
//    the License at
// 
//        http://www.apache.org/licenses/LICENSE-2.0
// 
//    Unless required by applicable law or agreed to in
//    writing, software distributed under the License is
//    distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
//    CONDITIONS OF ANY KIND, either express or implied.  See
//    the License for the specific language governing
//    permissions and limitations under the License.
// -------------------------------------------------------------
// 

typedef class vmm_atomic_gen;

class vmm_atomic_gen_callbacks #(type T = `VMM_DATA, C=vmm_channel_typed#(T), string text = "") extends vmm_xactor_callbacks; 
   virtual task post_inst_gen (vmm_atomic_gen #(T,C,text)   gen, 
                             T                   obj, 
                             ref bit             drop); 
   endtask 
endclass 

class vmm_atomic_gen_base extends `VMM_XACTOR;
     function new(string name,
                  string       inst, 
                int          stream_id = -1
                 `VMM_XACTOR_NEW_ARGS); 
      super.new(name, inst, stream_id `VMM_XACTOR_NEW_CALL);  
     endfunction

     virtual function void Xset_blueprintX(vmm_data tr);
     endfunction

endclass

class vmm_atomic_gen #(type T = `VMM_DATA, C=vmm_channel_typed#(T), string text = "") extends vmm_atomic_gen_base;
   int unsigned stop_after_n_insts; 
   typedef enum int {GENERATED, DONE} symbols_e; 
 
   T randomized_obj; 
   C out_chan;
 
   local int scenario_count; 
   local int obj_count; 
 
   function new(string       inst, 
                int          stream_id = -1, 
                C out_chan  = null `VMM_XACTOR_NEW_ARGS); 
      super.new({text, " Atomic Generator"}, inst, stream_id `VMM_XACTOR_NEW_CALL); 
      if (out_chan == null) begin 
          out_chan = new({text, " Atomic Generator output channel"}, 
                         inst); 
      `VMM_OBJECT_SET_PARENT(out_chan, this) 
      end 
      this.out_chan = out_chan; 
      this.out_chan.set_producer(this);
      this.log.is_above(this.out_chan.log); 
 
      this.scenario_count = 0; 
      this.obj_count = 0; 
      this.stop_after_n_insts = 0; 
 
      this.notify.configure(GENERATED, vmm_notify::ONE_SHOT); 
      this.notify.configure(DONE, vmm_notify::ON_OFF); 
      this.randomized_obj = new; 
      `VMM_OBJECT_SET_PARENT(randomized_obj, this) 
   endfunction: new 
 
   virtual function void Xset_blueprintX(vmm_data tr);
      if (!$cast(randomized_obj, tr)) begin
         `vmm_fatal(log, "Type mismatch!! Unable to set the blueprint object to randomized_obj");
      end
   endfunction

   virtual task inject(T obj, 
                       ref bit    dropped); 
      dropped = 0; 
 
      `vmm_callback(vmm_atomic_gen_callbacks#(T,C,text),post_inst_gen(this, obj, dropped)); 
 
      if (!dropped) begin 
         this.obj_count++; 
         this.notify.indicate(GENERATED, obj); 
         this.out_chan.put(obj); 
      end 
   endtask: inject 
 
   virtual function void reset_xactor(vmm_xactor::reset_e rst_type = SOFT_RST); 
      super.reset_xactor(rst_type); 
 
      this.out_chan.flush(); 
      this.scenario_count = 0; 
      this.obj_count = 0; 
 
      if (rst_type >= FIRM_RST) begin 
         this.notify.reset( , vmm_notify::HARD); 
      end 
 
      if (rst_type >= HARD_RST) begin 
         this.stop_after_n_insts = 0; 
         this.randomized_obj     = new; 
      end 
   endfunction: reset_xactor 
 
   virtual protected task main(); 
      bit dropped; 
 
      fork 
         super.main(); 
      join_none 
 
      while (this.stop_after_n_insts <= 0 || 
             this.obj_count < this.stop_after_n_insts) begin 
 
         this.wait_if_stopped(); 
 
         this.randomized_obj.stream_id   = this.stream_id; 
         this.randomized_obj.scenario_id = this.scenario_count; 
         this.randomized_obj.data_id     = this.obj_count; 
 
         if (!this.randomized_obj.randomize()) begin 
            `vmm_fatal(this.log, "Cannot randomize atomic instance"); 
            continue; 
         end 
 
         begin 
            T obj; 
 
            $cast(obj, this.randomized_obj.copy()); 
            this.inject(obj, dropped); 
         end 
      end 
 
      this.notify.indicate(DONE); 
      this.notify.indicate(XACTOR_STOPPED); 
      this.notify.indicate(XACTOR_IDLE); 
      this.notify.reset(XACTOR_BUSY); 
      this.scenario_count++; 
   endtask: main 
 
endclass

